#include "gtx31x_iic.h"

#if _KEYBOARD_FUNCTION_ENABLE_

/**
 * @brief 拉高SDA总线
 *
 */
static void Gtx31xIicSdaHight(void);

/**
 * @brief 拉低SDA总线
 *
 */
static void Gtx31xIicSdaLow(void);

/**
 * @brief 获取SDA总线电平状态
 *
 * @return 管脚电平状态
 */
static bool Gtx31xIicSdaGet(void);

/**
 * @brief 拉高SCL总线
 *
 */
static void Gtx31xIicSclHight(void);

/**
 * @brief 拉低SCL总线
 *
 */
static void Gtx31xIicSclLow(void);

/**
 * @brief IIC延时
 *
 * @param Time - 延时时间
 */
static void Gtx31xIicDelay(uint32_t Time);

/**
 * @brief 模拟IIC发起起始信号
 *
 */
static void Gtx31xIicStart(void);

/**
 * @brief 模拟IIC发送停止信号
 *
 */
static void Gtx31xIicStop(void);

/**
 * @brief 等待应答信号
 *
 * @return bool - 应答码（true：应答 false：非应答）
 */
static bool Gtx31xIicWaitAck(void);

/**
 * @brief 产生应答信号
 *
 */
static void Gtx31xIicAck(void);

/**
 * @brief 产生非应答信号
 *
 */
static void Gtx31xIicNoAck(void);

/**
 * @brief iic发送一字节
 *
 * @param Data - 发送的字节
 */
static void Gtx31xIicSendByte(uint8_t Data);

/**
 * @brief iic读取一字节
 *
 * @return uint8_t - 寄存器返回数值
 */
static uint8_t Gtx31xIicReadByte(void);

static void Gtx31xIicSdaHight(void)
{
  Gtx31xSetSdaPinLevel(true);
}

static void Gtx31xIicSdaLow(void)
{
  Gtx31xSetSdaPinLevel(false);
}

static bool Gtx31xIicSdaGet(void)
{
  return Gtx31xGetSdaPinLevel();
}

static void Gtx31xIicSclHight(void)
{
  Gtx31xSetSclPinLevel(true);
}

static void Gtx31xIicSclLow(void)
{
  Gtx31xSetSclPinLevel(false);
}

static void Gtx31xIicDelay(uint32_t Time)
{
  Gtx31xDelayUs(Time);
}

static void Gtx31xIicStart(void)
{
  Gtx31xIicSdaHight();
  Gtx31xIicSclHight();
  Gtx31xIicDelay(GTX31X_IIC_IO_DELAY_TIME);

  Gtx31xIicSdaLow();
  Gtx31xIicDelay(GTX31X_IIC_IO_DELAY_TIME);
  Gtx31xIicSclLow();
}

static void Gtx31xIicStop(void)
{
  Gtx31xIicSclLow();
  Gtx31xIicSdaLow();
  Gtx31xIicDelay(GTX31X_IIC_IO_DELAY_TIME);

  Gtx31xIicSclHight();
  Gtx31xIicSdaHight();
  Gtx31xIicDelay(GTX31X_IIC_IO_DELAY_TIME);
}

static bool Gtx31xIicWaitAck(void)
{
  uint8_t ucErrTime = 0;

  Gtx31xIicSdaHight();
  Gtx31xIicDelay(GTX31X_IIC_IO_DELAY_TIME);
  Gtx31xIicSclHight();
  Gtx31xIicDelay(GTX31X_IIC_IO_DELAY_TIME);

  Gtx31xConfigurationSdaInput();
  while (Gtx31xIicSdaGet() == true)
  {
    ucErrTime++;
    if (ucErrTime > 250)
    {
      Gtx31xIicStop();
      return false;
    }
  }

  Gtx31xConfigurationSdaOutput();
  Gtx31xIicSclLow();

  return true;
}

static void Gtx31xIicAck(void)
{
  Gtx31xIicSclLow();
  Gtx31xIicSdaLow();
  Gtx31xIicDelay(GTX31X_IIC_IO_DELAY_TIME);

  Gtx31xIicSclHight();
  Gtx31xIicDelay(GTX31X_IIC_IO_DELAY_TIME);
  Gtx31xIicSclLow();
}

static void Gtx31xIicNoAck(void)
{
  Gtx31xIicSclLow();
  Gtx31xIicSdaHight();
  Gtx31xIicDelay(GTX31X_IIC_IO_DELAY_TIME);

  Gtx31xIicSclHight();
  Gtx31xIicDelay(GTX31X_IIC_IO_DELAY_TIME);
  Gtx31xIicSclLow();
}

static void Gtx31xIicSendByte(uint8_t Data)
{
  Gtx31xIicSclLow();

  for (uint8_t i = 0; i < 8; i++)
  {
    ((Data << i) & 0x80) ? Gtx31xIicSdaHight() : Gtx31xIicSdaLow();
    Gtx31xIicDelay(GTX31X_IIC_IO_DELAY_TIME);

    Gtx31xIicSclHight();
    Gtx31xIicDelay(GTX31X_IIC_IO_DELAY_TIME);
    Gtx31xIicSclLow();
    Gtx31xIicDelay(GTX31X_IIC_IO_DELAY_TIME);
  }
}

static uint8_t Gtx31xIicReadByte(void)
{
  uint8_t Data = 0;

  Gtx31xConfigurationSdaInput();
  for (uint8_t i = 0; i < 8; i++)
  {
    Gtx31xIicSclLow();
    Gtx31xIicDelay(GTX31X_IIC_IO_DELAY_TIME);
    Gtx31xIicSclHight();

    Data <<= 1;
    Data |= (Gtx31xIicSdaGet() == true) ? 1 : 0;
    Gtx31xIicDelay(GTX31X_IIC_IO_DELAY_TIME);
  }

  Gtx31xConfigurationSdaOutput();

  return Data;
}

void Gtx31xIicWriteOneByte(uint8_t SlaveAddr, uint8_t WriteAddr, uint8_t InData)
{
  Gtx31xIicStart();

  Gtx31xIicSendByte(SlaveAddr);
  Gtx31xIicWaitAck();
  Gtx31xIicSendByte(WriteAddr);
  Gtx31xIicWaitAck();

  Gtx31xIicSendByte(InData);
  Gtx31xIicWaitAck();

  Gtx31xIicStop();
}

uint8_t Gtx31xIicReadOneByte(uint8_t SlaveAddr, uint8_t ReadAddr)
{
  uint8_t RegByte = 0;

  Gtx31xIicStart();
  Gtx31xIicSendByte(SlaveAddr);
  Gtx31xIicWaitAck();
  Gtx31xIicSendByte(ReadAddr);
  Gtx31xIicWaitAck();

  Gtx31xIicStart();
  Gtx31xIicSendByte(SlaveAddr + 1);
  Gtx31xIicWaitAck();

  RegByte = Gtx31xIicReadByte();
  Gtx31xIicNoAck();

  Gtx31xIicStop();

  return RegByte;
}

void Gtx31xIicWriteBytes(uint8_t SlaveAddr, uint8_t WriteAddr, const void *pInData, uint16_t InSize)
{
  uint8_t *pMessageData = (uint8_t *)pInData;

  if ((pInData != NULL) && (InSize != 0))
  {
    Gtx31xIicStart();

    Gtx31xIicSendByte(SlaveAddr);
    Gtx31xIicWaitAck();
    Gtx31xIicSendByte(WriteAddr);
    Gtx31xIicWaitAck();

    for (uint16_t i = 0; i < InSize; i++)
    {
      Gtx31xIicSendByte(pMessageData[i]);
      Gtx31xIicWaitAck();
    }

    Gtx31xIicStop();
  }
}

void Gtx31xIicReadBytes(uint8_t SlaveAddr, uint8_t ReadAddr, void *pOutData, uint16_t OutSize)
{
  uint16_t i = 0;
  uint8_t *pMessageData = (uint8_t *)pOutData;

  if ((pOutData != NULL) && (OutSize != 0))
  {
    Gtx31xIicStart();
    Gtx31xIicSendByte(SlaveAddr);
    Gtx31xIicWaitAck();
    Gtx31xIicSendByte(ReadAddr);
    Gtx31xIicWaitAck();

    Gtx31xIicStart();
    Gtx31xIicSendByte(SlaveAddr + 1);
    Gtx31xIicWaitAck();

    for (i = 0; i < OutSize - 1; i++)
    {
      pMessageData[i] = Gtx31xIicReadByte();
      Gtx31xIicAck();
    }

    pMessageData[i] = Gtx31xIicReadByte();
    Gtx31xIicNoAck();

    Gtx31xIicStop();
  }
}

#endif
